#pragma once

#include <iostream>
#include <string>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "../Common/log.hpp"
#include "../Common/util.hpp"

namespace ns_runner
{
    using namespace ns_log;
    using namespace ns_util;
    class Runner
    {
    public:
        Runner()
        {}
        ~Runner()
        {}
        static int SetProLimit(int _cpu_limit,int _mem_limit)
        {
          struct rlimit cpu_limit;
          cpu_limit.rlim_max = RLIM_INFINITY;
          cpu_limit.rlim_cur = _cpu_limit;

          struct rlimit mem_limit;
          mem_limit.rlim_max = RLIM_INFINITY;
          mem_limit.rlim_cur = _mem_limit * 1024;//KB转字节

          setrlimit(RLIMIT_CPU,&cpu_limit);//设置CPU资源
          setrlimit(RLIMIT_AS,&mem_limit);//设置内存资源
        }
        static int Run(std::string file_name,int _cpu_limit,int _mem_limit)
        {
          std::string _execute = PathUtil::Exec(file_name);
          umask(0);
          int _stdin = open(PathUtil::Stdin(file_name).c_str(),O_CREAT|O_WRONLY,0644);
          int _stdout = open(PathUtil::Stdout(file_name).c_str(),O_CREAT|O_WRONLY,0644);
          int _stderr = open(PathUtil::Stderr(file_name).c_str(),O_CREAT|O_WRONLY,0644);
          if(_stdin<0||_stdout<0||_stderr<0)
          {
            close(_stdin);
            close(_stdout);
            close(_stderr);
            LOG(ERROR)<<"创建打开运行生成的临时文件失败"<<"\n";
            exit(-1);
          }
          pid_t pid = fork();
          if(pid < 0)
          {
            LOG(ERROR) << "资源受限，创建子进程失败" << "\n";
            exit(-2);
          }
          else if(pid == 0)
          {

            dup2(_stdin,0);
            dup2(_stdout,1);
            dup2(_stderr,2);

            SetProLimit(_cpu_limit,_mem_limit);//限制进程资源，当资源超过设置则会发送信号，父进程会捕获信号返回
            execl(_execute.c_str(),_execute.c_str(),"-std=c++11",nullptr);//进程替换执行程序
            exit(1);
          }
          else
          {
            close(_stdin);
            close(_stdout);
            close(_stderr);
            //父进程需要判断是否成功运行可执行文件
            int status = 0;
            waitpid(pid,&status,0);
            /*
                程序运行异常，一定会收到信号！
                返回值 > 0：程序运行异常，退出时收到了信号，返回值就是对应的信号编号
                返回值 = 0：程序运行正常结束，运行结果保存在了对应的临时文件中
                返回值 < 0：内部错误
            */
            LOG(INFO)<<"程序运行完毕,收到的信号为:"<< (status & 0x7F) <<"\n";
            return status & 0x7F;
          }
        }
    };
}